package com.example.data_receiver.config;

import io.jsonwebtoken.ExpiredJwtException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //private final HttpsProperties httpsProperties;
    private final TokenConfig tokenConfig;

    @Autowired
    private Environment environment;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 添加token过滤器
        http.addFilterBefore(new JwtRequestFilter(tokenConfig), UsernamePasswordAuthenticationFilter.class);

        http
                .requiresChannel()
                .anyRequest().requiresInsecure()
                .and();
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/data/receive/batch/*").permitAll()
                .antMatchers("/data/kask/getToken").permitAll()
                .antMatchers("/data/kask/kaskPushData**").permitAll()
                .anyRequest().authenticated()
                .and();
        http.httpBasic().disable();
        http.formLogin().disable();
    }
}


// 添加 JwtRequestFilter 类
class JwtRequestFilter extends OncePerRequestFilter {
    private final TokenConfig tokenConfig;

    public JwtRequestFilter(TokenConfig tokenConfig) {
        this.tokenConfig = tokenConfig;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;
        String jwtToken = null;
        // JWT Token 格式为 "Bearer token". 去掉 Bearer 字符串
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = tokenConfig.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                writeErrorResponse(response, "Token无效", 401);
                return;
            } catch (ExpiredJwtException e) {
                writeErrorResponse(response, "Token已过期", 401);
                return;
            }
        }

        // 验证token
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            if (tokenConfig.validateToken(jwtToken, username)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        username, null, new ArrayList<>());
                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            } else {
                writeErrorResponse(response, "Token校验失败", 401);
                return;
            }
        }
        chain.doFilter(request, response);
    }

    private void writeErrorResponse(HttpServletResponse response, String message, int code) throws IOException {
        response.setStatus(code);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"status\":\"error\",\"code\":" + code + ",\"message\":\"" + message + "\"}");
    }
}